
const path = require("path");
const fs = require("fs");
const chalk = require("chalk");
const ora = require("ora");
const NodeSSH = require("node-ssh").NodeSSH;
const shell = require("shelljs");
const inquirer = require("inquirer");
const compressing = require("compressing");
const CONFIG = require("./config");

const SSH = new NodeSSH();
let config;

const defaultLog = (log) =>
  console.log(chalk.blue(`---------------- ${log} ----------------`));
const errorLog = (log) =>
  console.log(chalk.red(`---------------- ${log} ----------------`));
const successLog = (log) =>
  console.log(chalk.green(`---------------- ${log} ----------------`));

const compileDist = async () => {
  const loading = ora(defaultLog("项目开始打包")).start();
  shell.cd(path.resolve(__dirname, "../"));
  const res = await shell.exec(`npm run ${config.script}`);
  loading.clear();
  if (res.code === 0) {
    successLog("项目打包成功!");
  } else {
    errorLog("项目打包失败, 请重试!");
    process.exit();
  }
};

const zipDist = async () => {
  defaultLog("项目开始压缩");
  try {
    const distDir = path.resolve(__dirname, `../${config.publicPath}`);
    const distZipPath = path.resolve(__dirname, `../${config.publicPath}.zip`);
    await compressing.zip.compressDir(distDir, distZipPath);
    successLog("压缩成功!");
  } catch (error) {
    errorLog(error);
    errorLog("压缩失败, 退出程序!");
    process.exit();
  }
};

const connectSSH = async () => {
  const loading = ora(defaultLog("正在连接服务器")).start();
  try {
    await SSH.connect({
      host: config.host,
      username: config.username,
      password: config.password,
    });
    successLog("SSH连接成功!");
  } catch (error) {
    errorLog(error);
    console.log(error);
    errorLog("SSH连接失败!");
    process.exit();
  }
  loading.clear();
};

const runCommand = async (command) => {
  await SSH.exec(command, [], { cwd: config.path });
};


const clearOldFile = async () => {
  const date = new Date().getDate();
  const mouth = new Date().getMonth();
  await runCommand(`mkdir -p ${config.publicPath}`);
  await runCommand(
    `cp -r ${config.publicPath} ${config.publicPath}_${mouth + 1}${date}`
  );
  await runCommand(`rm -rf ${config.publicPath}`);
};

const uploadZipBySSH = async () => {
  await connectSSH();
  await clearOldFile();
  const loading = ora(defaultLog("准备上传文件")).start();
  try {
    const distZipPath = path.resolve(__dirname, `../${config.publicPath}.zip`);
    await SSH.putFiles([
      { local: distZipPath, remote: config.path + `/${config.publicPath}.zip` },
    ]);
    successLog("上传成功!");
    loading.text = "正在解压文件";
    await runCommand(`unzip ./${config.publicPath}.zip`);
    await runCommand(`rm -rf ./${config.publicPath}.zip`);
    SSH.dispose();
  } catch (error) {
    errorLog(error);
    errorLog("上传失败!");
    process.exit();
  }
  loading.clear();
};

const clearZipDist = async () => {
  const distZipPath = path.resolve(__dirname, `../${config.publicPath}.zip`);
  fs.unlink(distZipPath, () => { });
};

const runUploadTask = async () => {
  await compileDist();
  await zipDist();

  await uploadZipBySSH();

  await clearZipDist();

  successLog("部署成功!");
  process.exit();
};

const checkConfig = (conf) => {
  const checkArr = Object.entries(conf);
  checkArr.map((it) => {
    const key = it[0];
    if (key === "PATH" && conf[key] === "/") {
      errorLog("PATH 不能是服务器根目录!");
      process.exit();
    }
    if (!conf[key]) {
      errorLog(`配置项 ${key} 不能为空`);
      process.exit();
    }
  });
};

async function inputPwd () {
  const data = await inquirer.prompt([
    {
      type: "password",
      name: "password",
      message: "服务器密码",
    },
  ]);
  return data.password;
}

async function initInquirer () {
  const data = await inquirer.prompt([
    {
      type: "list",
      message: "请选择发布环境",
      name: "env",
      choices: CONFIG.servers.map((sever) => ({
        name: sever.name,
        value: sever.name,
      })),
    },
  ]);
  config = CONFIG.servers.find((server) => data.env === server.name);
  if (config) {
    if (!config.password) {
      config.password = await inputPwd();
    }
    checkConfig(config);
    runUploadTask();
  } else {
    errorLog("未找到该环境");
  }
}

initInquirer();
